
#include <pthread.h>
#include "ka-system/timer.h"
#include "ka-system/thread.h"

using namespace ka;

Mutex::Mutex()
: _data(NULL) {
    pthread_mutex_t *handle = (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t));
    if (handle && 0 == pthread_mutex_init(handle, NULL)) {
        _data = handle;
    }
    else {
        free(handle);
    }
}

Mutex::~Mutex() {
    if (_data) {
        pthread_mutex_destroy((pthread_mutex_t *)_data);
        free(_data);
    }
}

bool Mutex::lock(uint64_t timeoutMillis) {
    bool r = false;
    uint64_t time = UINT64_C(0);
    if (_data) {
        do {
            if (0 == pthread_mutex_trylock((pthread_mutex_t *)_data)) {
                r = true;
                break;
            }
            else {
                pthread_yield_np();
            }
            uint64_t now = getSystemTicks();
            if (time > 0) {
                uint64_t delta = (now - time);
                if (delta > timeoutMillis) {
                    delta = timeoutMillis;
                }
                timeoutMillis -= delta;
            }
            time = now;
        }
        while (timeoutMillis > 0);
    }
    return r;
}

void Mutex::unlock() {
    if (_data) {
        pthread_mutex_unlock((pthread_mutex_t *)_data);
    }
}


ThreadLocal::ThreadLocal() 
: _data(NULL) {
    pthread_key_t *key = (pthread_key_t *)malloc(sizeof(pthread_key_t));
    if (key && 0 == pthread_key_create(key, NULL)) {
        _data = key;
    }
    else {
        free(key);
    }
}

ThreadLocal::~ThreadLocal() {
    free(_data);
}

void *ThreadLocal::getPointer() {
    void *ptr = NULL;
    if (_data) {
        ptr = pthread_getspecific(*((pthread_key_t *)_data));
    }
    return ptr;
}

void ThreadLocal::setPointer(const void *ptr) {
    if (_data) {
        pthread_setspecific(*((pthread_key_t *)_data), ptr);
    }
}